﻿// News Framework
// (C) Tanzim Saqib. Oct 25, 2010.
// http://TanzimSaqib.com | http://newsfx.codeplex.com

namespace TanzimSaqib.NewsFramework
{
    using System;
    using System.Windows;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Shell;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Controls;
    using System.ComponentModel;

    public partial class Fx
    {
        private static Fx fx;

        private Fx()
        {
            Check.If(RootApp == null, () =>
            {
                throw new InvalidOperationException(FxConstants.FxInitializeWasNotCalled);
            });

            InitializePhoneApplication();

            if(bool.Parse(Settings["ClearCacheOnStartUp"]))
            {
                StorageHelper.ClearCache();
            }
        }

        public static Fx Instance
        {
            get { return fx ?? (fx = new Fx()); }
        }

        public static void Initialize(Application app, IRssItemParser rssParser)
        {
            RootApp = app;
            ExtendedParser = rssParser;
            app.Startup += Application_Startup;
            app.Exit += Application_Exit;
            app.UnhandledException += Application_UnhandledException;
            Instance.RegisterEvents();
        }

        #region Properties

        internal static Application RootApp { get; set; }

        /// <summary>
        /// Provides easy access to the root frame of the Phone Application.
        /// </summary>
        /// <returns>The root frame of the Phone Application.</returns>
        internal PhoneApplicationFrame RootFrame { get; private set; }

        internal PhoneApplicationService RootService { get; set; }

        internal EventHandler<ActivatedEventArgs> OnActivated { get; set; }
        internal EventHandler<DeactivatedEventArgs> OnDeactivated { get; set; }
        internal EventHandler<LaunchingEventArgs> OnLaunch { get; set; }
        internal EventHandler<ClosingEventArgs> OnClose { get; set; }

        public Page RootPage 
        { 
            get { return Instance.RootFrame.Content as Page; }
        }

        private string _Namespace;
        internal string Namespace { get { return _Namespace ?? (_Namespace = Application.Current.ToString().Replace(".App", string.Empty)); } }

        private static IAppSettings _Settings;
        public IAppSettings Settings { get { return _Settings ?? (_Settings = new AppSettings(Namespace)); } }

        private static Feeds _Feeds;
        internal Feeds Feeds { get { return _Feeds ?? (_Feeds = new Feeds(Namespace, Settings[FxConstants.FeedsPath])); } }

        public static bool IsDesignMode { get { return Application.Current.RootVisual != null && DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual); } }

        internal static IRssItemParser ExtendedParser { get; set; }

        internal int RssItemCount
        {
            get { return int.Parse(Instance.Settings[FxConstants.RssItemCount]); }
        }

        #endregion

        #region Phone application initialization

        // Avoid double-initialization
        private bool phoneApplicationInitialized = false;

        // Do not add any additional code to this method
        private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            RootService = new PhoneApplicationService();
            RootService.Activated += RootService_Activated;
            RootService.Deactivated += RootService_Deactivated;
            RootService.Launching += RootService_Launching;
            RootService.Closing += RootService_Closing;

            RootApp.ApplicationLifetimeObjects.Add(RootService);

            if (phoneApplicationInitialized)
                return;

            // Create the frame but don't set it as RootVisual yet; this allows the splash
            // screen to remain active until the application is ready to render.
            RootFrame = new PhoneApplicationFrame();
            RootFrame.Navigated += CompleteInitializePhoneApplication;

            // Handle navigation failures
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            // Ensure we don't initialize again
            phoneApplicationInitialized = true;
        }

        // Do not add any additional code to this method
        private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
        {
            // Set the root visual to allow the application to render
            if (RootApp.RootVisual != RootFrame)
                RootApp.RootVisual = RootFrame;

            // Remove this handler since it is no longer needed
            RootFrame.Navigated -= CompleteInitializePhoneApplication;
        }

        #endregion

        #region View Models

        private static MainPanoramaViewModel _MainPanoramaViewModel = null;
        internal static MainPanoramaViewModel MainPanoramaViewModel
        {
            get
            {
                // Delay creation of the view model until necessary
                return _MainPanoramaViewModel ?? (_MainPanoramaViewModel = new MainPanoramaViewModel());
            }
        }

        #endregion

        #region Event handlers

        private void RegisterEvents()
        {
            OnActivated += (s, e) => Instance.LoadDataModel(true);
            OnLaunch += (s, e) => Instance.LoadDataModel(false);
        }

        private static void Application_Startup(object sender, StartupEventArgs e)
        {
            //throw new NotImplementedException();
        }

        private static void Application_Exit(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
        }

        // Code to execute on Unhandled Exceptions
        private static void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
                System.Diagnostics.Debugger.Break();
            }
            else
            {
                MessageBox.Show(e.ExceptionObject.Message);
            }
        }

        // Code to execute if a navigation fails
        private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // A navigation has failed; break into the debugger
                System.Diagnostics.Debugger.Break();
            }
        }

        // Code to execute when the application is launching (eg, from Start)
        // This code will not execute when the application is reactivated
        private void RootService_Launching(object sender, LaunchingEventArgs e)
        {
            if (OnLaunch != null)
                OnLaunch(sender, e);
        }

        // Code to execute when the application is activated (brought to foreground)
        // This code will not execute when the application is first launched
        private void RootService_Activated(object sender, ActivatedEventArgs e)
        {
            if (OnActivated != null)
                OnActivated(sender, e);
        }

        // Code to execute when the application is deactivated (sent to background)
        // This code will not execute when the application is closing
        private void RootService_Deactivated(object sender, DeactivatedEventArgs e)
        {
            if (OnDeactivated != null)
                OnDeactivated(sender, e);
        }

        // Code to execute when the application is closing (eg, user hit Back)
        // This code will not execute when the application is deactivated
        private void RootService_Closing(object sender, ClosingEventArgs e)
        {
            if (OnClose != null)
                OnClose(sender, e);
        }

        #endregion

        #region Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentPage">Instance of current Page.</param>
        /// <param name="assemblyName">Assembly namespace containing the page.</param>
        /// <param name="pathToPage">Path to destination page. Example: /Page1.xaml</param>
        internal void GoToPageInAssembly(string assemblyName, string pathToPage)
        {
            Instance.RootFrame.Navigate(new Uri(FxConstants.DifferentAssemblyPath.FormatWith(assemblyName, pathToPage), UriKind.Relative));
        }

        #endregion

        #region Workflows

        internal void SaveFeedItems(Dictionary<string, Feed> feedItems)
        {
            var list = (from i in feedItems select i.Value).ToList();
            StorageHelper.SaveFile(FxConstants.FeedItemsXmlFileName, list);
        }

        internal Dictionary<string, Feed> ReadFeedItems()
        {
            var dictionary = new Dictionary<string, Feed>();
            var list = StorageHelper.ReadFile<List<Feed>>(FxConstants.FeedItemsXmlFileName);
            list.ForEach((feedItem) => dictionary.Add(feedItem.URL, feedItem));

            return dictionary;
        }

        internal Dictionary<string, RssItem> ReadRssItems()
        {
            var dictionary = new Dictionary<string, RssItem>();
            var list = StorageHelper.ReadFile<List<RssItem>>(FxConstants.RSSItemsXmlFileName);
            list.ForEach((rssItem) => dictionary.Add(rssItem.Link, rssItem));

            return dictionary;
        }

        private void LoadDataModel(bool onActivated)
        {

        }

        #endregion
    }
}
